package com.chenhy.server.filter;

import com.chenhy.server.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获取到请求头中的Token
        String token = request.getHeader(tokenHeader);

        // 这里是因为我们生成Token返回给前端时将Token和TokenHead返回给了前端
        // 前端会将这两个东西拼接起来然后再以拼接结果为参数放在请求头中发起请求
        if (token != null && token.startsWith(tokenHead)){
            // 截取出Token的有效部分
            String authToken = token.substring(tokenHead.length());
            // 从token中解析出username
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            // 如果解析出来的username不为空或SpringSecurity上下文中认证对象为空（未登录）
            // 这里就是判断Token是否有效的，如果有效就根据token中的username从数据库中查出UserDetails然后交给上下文
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                // 判断Token是否过期
                if (jwtTokenUtil.validateToken(authToken,userDetails)){
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                    // 这里不懂
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    // 将用户信息交给上下文
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }

        }
        // 放行（如果上下文中没有认证信息的话会被过滤链后续的过滤器处理）
        filterChain.doFilter(request,response);
    }
}
